#Copyright (c) 2025, Alibaba Cloud and its affiliates;
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.



# -*- coding: UTF-8 -*-
##TBD
import json
from datetime import datetime
from functools import wraps

import jwt
from flask import current_app as app
from flask import request
from flask import session

from extensions.exception import FceException
from common_libs.sqlitedb import delete_db, insert_db, UserToken, FCE_DB
from common_libs.helper import error_handler
from common_libs.helper import get_request_data


class Auth():
    def __init__(self):
        # super.__init__(self)
        return

    @staticmethod
    def update_token(token, time, username):
        #     """
        #     更新token
        #     :return: none
        #     """
        try:
            params = {
                "release_time": time,
                "expire_time": time + app.config['JWT_TOKEN_EXPIRES']
            }
            with app.app_context():
                ret = UserToken.query.filter_by(token=token).first()
                # app.logger.info('update_token 2')
                if ret != None:
                    UserToken.query.filter_by(token=token).update(params)
                    FCE_DB.session.commit()
                    return True
                else:
                    insert_db(
                        UserToken(release_time=params["release_time"], expire_time=params["expire_time"], token=token,
                                  user=username))
            return False
        except Exception as e:
            FceException("InvalidToken.Unauthorized")

    @staticmethod
    def delete_token(token):
        """
        删除token
        :return: (bool)
        """
        with app.app_context():
            res = UserToken.query.filter_by(token=token).first()
            if res != None:
                delete_db(res)
                return True
        return False

    @staticmethod
    def delete_token_by_username(username):
        """
        删除token
        :return: (bool)
        """
        with app.app_context():
            res = UserToken.query.filter_by(user=username).all()  # app.logger.info(res)
        try:
            for i in res:
                delete_db(i)
            return True
        except:
            return False

    @staticmethod
    def auth_expire(token):
        """
        用户过期时间验证
        :return: (bool)
        """
        with app.app_context():
            ret = UserToken.query.filter_by(token=token).first()
            if ret == None:
                FceException("InvalidToken.Unauthorized")

        expire_time = ret.expire_time
        now = int(datetime.now().timestamp())
        if now > expire_time:
            FceException("InvalidToken.Expired")
        session["expire_time"] = expire_time
        return True

    @staticmethod
    def release_auth_token(token, release_time, username):
        """
        用户刷新时间
        :return: (string)
        """
        return Auth.update_token(token, release_time, username)

    @staticmethod
    def encode_auth_token(username, password, login_time, secret_key=""):
        """
          生成认证Token
          :param username: string
          :return: string
        """
        try:
            payload = {
                # "exp": datetime.utcnow() + timedelta(seconds=app.config['JWT_TOKEN_EXPIRES']),
                # 'iat': datetime.utcnow(),
                # 'iss': 'ken',
                'login_time': login_time,  # int(datetime.now().timestamp()),
                'user_info': json.dumps({
                    'username': username
                    # 'password': password,
                })
            }
            token = jwt.encode(payload, secret_key, algorithm='HS256')
            Auth.update_token(token, int(login_time), username)
            return token
        except Exception as e:
            FceException("InvalidToken.Unauthorized")
            return e

    @staticmethod
    def decode_auth_token(auth_token, secret_key=""):
        """
        验证Token
        :param auth_token:
        :param secret_key:
        :return: (bool, string)
        """
        try:
            payload = jwt.decode(auth_token, secret_key, algorithms=['HS256'], options={
                'verify_exp': False
            })
            if (payload != None and 'user_info' in payload and 'username' in payload['user_info']):
                user_info = json.loads(payload['user_info'])
                session['user_info'] = {
                    "Account": user_info["username"]
                }
                return (True, "", payload)
            else:
                # error_handler(e)
                return (False, "InvalidToken.Unauthorized", {})
        except jwt.ExpiredSignatureError as e:
            error_handler(e)
            return (False, "InvalidToken.Unauthorized", {})
        except jwt.InvalidTokenError as e:
            error_handler(e)
            return (False, "InvalidToken.Unauthorized", {})

    @staticmethod
    def identify(authorization_token, secret_key=""):
        """
        用户鉴权
        :return: (bool, string, string, object)
        """
        if (authorization_token):
            (isAuthSuccess, code, data) = Auth.decode_auth_token(authorization_token, secret_key)
            is_expire_time = Auth.auth_expire(authorization_token)
            if isAuthSuccess == True and is_expire_time == True:
                return (True, code, data)
            return (False, "InvalidToken.Unauthorized", {})
        return (False, "InvalidToken.Unauthorized", {})

    @staticmethod
    def get_account_info(account):

        account_info = []

        users = UserToken.query.all()
        user_list = set([user.user for user in users])

        for user_name in user_list:

            user_info_expire = []
            user_info_all = UserToken.query.filter(UserToken.user == user_name)
            for user_info in user_info_all:
                if user_info.expire_time < int(datetime.now().timestamp()):
                    user_info_expire.append(user_info)

            user_info_list = [item for item in user_info_all if item not in user_info_expire]
            app.logger.info(f'user_name {user_name}; user_info_list: {user_info_list}; user_info_expire:'
                            f' {user_info_expire}')
            if user_info_expire:
                for expire_info in user_info_expire:
                    delete_db(expire_info)
            account_info.append({
                "user_name": user_name,
                "token_num": len(user_info_list),
                "state": "logging in" if len(user_info_list) else "logging out"
            })

        return account_info

def authorize():
    """
      Token 验证
    """

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            secret_key = app.config['SECRET_KEY']
            request_id = get_request_data('RequestId', '')
            username = request.form.get('Account', '')
            authorization_token = request.headers.get('Authorization', '')
            if request_id == "" or authorization_token == "":
                FceException("InvalidParameters", "RequestId")
            try:
                (is_success, error_code, data) = Auth.identify(authorization_token, secret_key)
                if not is_success:
                    FceException(error_code)
                else:
                    expire_time = session["expire_time"]
                    now = int(datetime.now().timestamp())
                    # # 自动更新token
                    if expire_time != None and (expire_time - now) < app.config['JWT_TOKEN_RELEASE']:
                        # app.logger.info('release authorization_token')
                        Auth.release_auth_token(authorization_token, now, username)

            except Exception as e:
                Auth.delete_token(authorization_token)
                FceException("InvalidToken.Unauthorized")
            return func(*args, **kwargs)

        return wrapper

    return decorator
